<?php

/**
 * Service class for tax module
 *
 *
 * @author Ishtiaque Shahrier <md.ishtiaque@newgenbd.net>
 * @package tax
 * @subpackage libraries
 */
class service_l_tax {

    public function __construct() {
        
    }

    /**
     * Returns tax exemptions for a specific product
     *
     * @param int|product_m_product $product_id_or_object
     * @return NULL|product_m_tax
     */
    public function get_exemption($product_id_or_object) {
        $product = get_object($product_id_or_object, "product_m_product");
        if ($product) {
            $product_tax_exemption = new exemption_m_tax();
            $product_tax_exemption->get_by_product_id($product->id);
            if ($product_tax_exemption->result_count()) {
                return $product_tax_exemption;
            } else {
                return NULL;
            }
        } else {
            return NULL;
        }
    }

    /**
     * Returns an array of tax amount indexed by tax class name
     * Returns NULL if theres no tax class
     *     
     * @param int|product_m_product $product_id_or_object
     * @param int $qty  quantity
     * @return NULL|array
     */
    public function calculate_product_tax($product_id_or_object, $qty=1, $use_this_price=NULL) {
        $tax_classes = $this->get_tax_classes();
        $arr = array();
        foreach ($tax_classes as $c) {
            $arr[$c->id] = 0.00;
        }
        if ($tax_classes !== NULL) {
            $product_taxes = $this->get_exemption($product_id_or_object);
            $product = get_object($product_id_or_object, "product_m_product");
            //that is all available tax classes appicable
            if ($product && $product->tax_free=="0") {
                foreach ($tax_classes as $c) {
                    $arr[$c->id] = get_tax_amount($c, ($use_this_price === NULL ? $product->get_price() : $use_this_price), $qty);
                }
                if ($product_taxes !== NULL) {
                    foreach ($product_taxes as $pt) {
                        $arr[$pt->tax_id] = (float) 0.00;
                    }
                }
            }
            return $arr;
        }else{
            return NULL;
        }
        
    }

    /**
     * Returns NULL is theres is no tax classes for the site else list
     * of tax classes for the site
     * 
     * @param int $site_id
     * @return NULL|array array of tax_m_tax indexed by id
     */
    public function get_tax_classes($site_id=NULL, $reload=FALSE) {
        static $tax_classes = NULL;
        static $_inited = FALSE;
        if ($reload === TRUE) {
            $tax_classes = NULL;
            $_inited = FALSE;
        }
        if ($tax_classes === NULL && $_inited === FALSE) {
            if ($site_id === NULL) {
                $site_id = service_l_core::get_current_site()->id;
            }
            $tax = new tax_m_tax();
            $tax->get_by_site_id($site_id);
            if ($tax->result_count() > 0) {
                $_arr = array();
                foreach ($tax as $t) {
                    $_arr[$t->id] = $t;
                }
                return ($tax_classes = $_arr);
            } else {
                $_inited = TRUE;
                return ($tax_classes = NULL);
            }
        } else {
            return $tax_classes;
        }
    }

    /**
     * Returns total tax amount for diferent tax classes for the all
     * ordered products only.
     *
     * @param int|order_m_order $order_id_or_obj
     * @return NULL|array i.e array('0'=>12.34 , '1'=>0.00) whereas 0=GST..1 may be PST
     */
    public function calculate_order_items_tax($order_id_or_obj) {
        $tax_classes = $this->get_tax_classes();
        if ($tax_classes !== NULL) {
            $order_srvice = new service_l_order();
            $items = $order_srvice->get_order_items($order_id_or_obj);
            $grouped_tax = array();
            //init tax classes with $0.0
            foreach ($tax_classes as $tc)
                $grouped_tax[$tc->id] = 0.00;
            //now if there are items
            if ($items !== NULL) {
                foreach ($items as $i) {
                    $ptax_amounts = $this->calculate_product_tax($i->get_product(), $i->qty, $i->unit_price);
                    if ($ptax_amounts !== NULL) {
                        foreach ($ptax_amounts as $c => $a) {
                            if (isset($grouped_tax[$c])) {
                                $grouped_tax[$c]+=$a;
                            }
                        }
                    }
                }
            }
            return $grouped_tax;
        } else {
            return NULL;
        }
    }

    /**
     * Depending on the global settings shipping  applies tax rate
     *
     * @param int|order_m_order $order_id_or_obj
     * @return NULL|array i.e array('0'=>12.34 , '1'=>0.00) whereas 0=GST..1 may be PST
     */
    public function calculate_order_shipping_tax($order_id_or_obj) {
        $tax_classes = $this->get_tax_classes();
        $grouped_tax = array();
        if ($tax_classes !== NULL) {
            $order_obj = get_object($order_id_or_obj, "order_m_order");
            $shipping_service = new shipping_manager();
            $info =  $shipping_service->get_shipping_info($order_obj);
            if($info){
                $cost =  $info->shipping_cost;
                foreach ($tax_classes as $tc){
                    $grouped_tax[$tc->id] = ($tc->rate/100) * $cost;
                }                
            }else{
                foreach ($tax_classes as $tc){
                    $grouped_tax[$tc->id] = 0.00;
                }
            }
            return $grouped_tax;
        }else{
            return NULL;
        }
    }

    /**
     * Clears all tax information for the passed order
     *
     * @param int|order_m_order $order_id_or_object
     * @param string|NULL $group i.e shipping, items see module_u_tax constrants
     * @param int|NULL $tax_class_id
     * @return NULL|TRUE|FALSE
     */
    public function clear_order_taxes($order_id_or_object,$group=NULL,$tax_class_id=NULL) {
        $order_obj = get_object($order_id_or_object, "order_m_order");
        if ($order_obj) {
            $order_tax = new order_tax_m_tax();
            $order_tax->where("order_id",$order_obj->id);
            if($group!==NULL){
                $order_tax->where("group",$group);
            }
            if($tax_class_id!==NULL){
                $order_tax->where("tax_id",$tax_class_id);
            }
            return $order_tax->get()->delete_all() ? TRUE : FALSE;
        } else {
            return NULL;
        }
    }

    /**
     * Saves order products/items taxes
     *
     * @param int|order_m_order $order_id_or_obj
     * @param array $grouped_tax_amounts array fo tax amounts indexed by tax class id
     * @return NULL|TRUE|FALSE
     */
    public function save_order_item_taxes($order_id_or_obj, array $grouped_tax_amounts) {

        $order_obj = get_object($order_id_or_obj, "order_m_order");

        if ($order_obj) {
            $this->clear_order_taxes($order_obj,  module_u_tax::TAX_ITEMS);
            if (count($grouped_tax_amounts)) {
                $order_tax = new order_tax_m_tax();
                foreach ($grouped_tax_amounts as $id => $amount) {
                    $order_tax->order_id = $order_obj->id;
                    $order_tax->tax_id = $id;
                    $order_tax->amount = $amount;
                    $order_tax->group  = module_u_tax::TAX_ITEMS;
                    $order_tax->save_as_new();
                }
                return TRUE;
            }else{
                return FALSE;
            }
        } else {
            return NULL;
        }
    }

    /**
     * Saves order shipping taxes.It does clear out previous rate info before saving new
     *
     * @param int|order_m_order $order_id_or_obj
     * @param array $grouped_tax_amounts array fo tax amounts indexed by tax class id
     * @return NULL|TRUE|FALSE
     */
    public function save_order_shipping_tax($order_id_or_obj, array $grouped_tax_amounts){
        $order_obj = get_object($order_id_or_obj, "order_m_order");
        if ($order_obj) {
            $this->clear_order_taxes($order_obj,  module_u_tax::TAX_SHIPPING);
            if (count($grouped_tax_amounts)) {
                $order_tax = new order_tax_m_tax();
                foreach ($grouped_tax_amounts as $id => $amount) {
                    $order_tax->order_id = $order_obj->id;
                    $order_tax->tax_id = $id;
                    $order_tax->amount = $amount;
                    $order_tax->group  = module_u_tax::TAX_SHIPPING;
                    $order_tax->save_as_new();
                }
                return TRUE;
            }else{
                return FALSE;
            }
        } else {
            return NULL;
        }
    }

    /**
     * Returns the order tax amount,result can be filtered by group name and tax class
     *
     * @param int|NULL $order_id
     * @param string|NULL $group_name
     * @param int|nuLL $tax_class_id
     * @return NULL|array indexed by tax id
     */
    public function get_order_tax($order_id,$group_name=NULL,$tax_class_id=NULL){
        $order_tax = new order_tax_m_tax();
        $order_tax->where("order_id",$order_id);
        if($group_name)
            $order_tax->where("group",$group_name);
        if($tax_class_id)
            $order_tax->where("tax_id",$tax_class_id);
        $order_tax->get();
        
        if($order_tax->result_count()>0){            
            $arr = array();
            foreach($order_tax as $ot){
                if(isset($arr[$ot->tax_id])){
                    $arr["$ot->tax_id"] += (float)$ot->amount;
                }else{
                    $arr["$ot->tax_id"]  = (float)$ot->amount;
                }
            }
            return $arr;
        }else{
            return NULL;
        }
    }
}

?>